﻿using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Asn1.GM;
using System.Text;

namespace LicenseDemo.Licenses;

/// <summary>
/// 生成SM2密钥对
/// </summary>
class Sm2KeyPairGenerator
{
    #region 单例模式
    // 使用 Lazy<T> 实现懒加载
    private static readonly Lazy<Sm2KeyPairGenerator> _instance = new(() => new Sm2KeyPairGenerator());

    // 私有构造函数，防止外部实例化
    private Sm2KeyPairGenerator() { }

    // 公共静态属性，用于访问单例实例
    public static Sm2KeyPairGenerator Instance => _instance.Value;
    #endregion

    #region 密钥对生成算法
    // 使用【sm2p256v1】曲线,获取SM2曲线的X9ECParameters对象
    private static readonly X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");

    // 使用X9ECParameters对象创建ECDomainParameters对象
    private static readonly ECDomainParameters domainParams = new(
        x9ECParameters.Curve,
        x9ECParameters.G,
        x9ECParameters.N,
        x9ECParameters.H,
        x9ECParameters.GetSeed()
    );

    private static readonly ECKeyPairGenerator generator = new();

    /// <summary>
    /// 生成SM2密钥对（公钥，私钥）
    /// </summary>
    /// <returns></returns>
    public AsymmetricCipherKeyPair GenerateKeyPair()
    {
        generator.Init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));
        return generator.GenerateKeyPair();
    }
    #endregion

    /// <summary>
    /// 测试，输出密钥对信息
    /// </summary>
    public void KeyPairInfo()
    {
        StringBuilder strBuilder = new(128);

        strBuilder.AppendLine("Hello, SM2KeyPairGenerator!");
        // 输出曲线名称
        strBuilder.AppendLine("Curve Name: sm2p256v1");

        // 输出曲线参数
        strBuilder.AppendLine($"Curve: {x9ECParameters.Curve}");
        strBuilder.AppendLine($"G:{x9ECParameters.G}");
        strBuilder.AppendLine($"N:{x9ECParameters.N}");
        strBuilder.AppendLine($"H:{x9ECParameters.H}");

        byte[]? seed = x9ECParameters.GetSeed();
        if (seed != null)
        {
            strBuilder.AppendLine($"Seed:{BitConverter.ToString(seed)}");
        }

        // 输出ECDomainParameters对象
        strBuilder.AppendLine($"ECDomainParameters: {domainParams}");

        Console.WriteLine(strBuilder.ToString());
    }
}
